function [sdm, sdms] = spmmat2sdm(spmmat, sdmfile)
% spmmat2sdm  - convert a SPM.mat file into BV's SDM file(s)
%
% FORMAT:       [sdm, sdms] = spmmat2sdm(spmmat, sdmfile)
%
% Input fields:
%
%       spmmat      either SPM.mat filename or struct with fields
%        .SPM       1x1 struct containing loaded struct
%             - or -
%        .xX        design structure
%          .X       design matrix
%          .name    names of predictors
%
% Output fields:
%
%       sdm         SDM object of first session
%       sdms        cell array with SDM objects of all session
%
% See also spmmat2prt

% Version:  v0.7b
% Build:    7090520
% Date:     Sep-05 2007, 8:35 PM CEST
% Author:   Jochen Weber, Brain Innovation, B.V., Maastricht, NL
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

% argument check
if nargin < 2 || ...
   (~ischar(spmmat) && ...
    ~isstruct(spmmat)) || ...
    isempty(spmmat) || ...
   ~ischar(sdmfile) || ...
    isempty(sdmfile)
    error( ...
        'BVQXtools:BadArgument', ...
        'Missing or bad argument. Try ''help %s''.', ...
        mfilename ...
    );
end

% what is spmmat
if ischar(spmmat)
    try
        spmmat = load(spmmat(:)');
        spmmat.SPM;
    catch
        error( ...
            'BVQXtools:BadArgument', ...
            'Invalid SPM.mat filename given.' ...
        );
    end
end
if numel(spmmat) ~= 1
    error( ...
        'BVQXtools:BadArgument', ...
        'Bad dim/size of spmmat argument.' ...
    );
end
if isfield(spmmat, 'SPM')
    spmmat = spmmat.SPM;
end
if numel(spmmat) ~= 1 || ...
   ~isfield(spmmat, 'xX') || ...
   ~isstruct(spmmat.xX) || ...
    numel(spmmat.xX) ~= 1 || ...
   ~isfield(spmmat.xX, 'X') || ...
    isempty(spmmat.xX.X) || ...
   (~isa(spmmat.xX.X, 'double') && ...
    ~isa(spmmat.xX.X, 'single')) || ...
   ~isfield(spmmat.xX, 'name') || ...
   ~iscell(spmmat.xX.name) || ...
    numel(spmmat.xX.name) ~= size(spmmat.xX.X, 2)
    error( ...
        'BVQXtools:BadArgument', ...
        'Invalid SPM.mat structure given.' ...
    );
end
xX = spmmat.xX.X;
nampred = spmmat.xX.name(:);

% parse session numbers
numpred = numel(nampred);
sespred = zeros(1, numpred);
baspred = zeros(1, numpred);
for pc = 1:numpred
    if ~ischar(nampred{pc}) || ...
        numel(nampred{pc}) < 7 || ...
       ~strcmpi(nampred{pc}(1:3), 'sn(')
        error( ...
            'BVQXtools:BadArgument', ...
            'Session not detectable from predictor names.' ...
        );
    end
    snnum = nampred{pc}(4:5);
    snnum(snnum == ')') = [];
    try
        snnum = str2double(snnum);
    catch
        error( ...
            'BVQXtools:BadArgument', ...
            'Session not detectable from predictor names.' ...
        );
    end
    sespred(pc) = snnum;
    if ~isempty(regexpi(nampred{pc}, '.*constant$'))
        baspred(pc) = 1;
    end
end
sessno = numel(unique(sespred));

% generate SDMs
[sdmabs{1:2}] = isabsolute(sdmfile(:)');
[sdmp{1:3}] = fileparts(sdmabs{2});
sdms = cell(1, sessno);
for sc = 1:sessno
    
    % get baseline column (to detect time indices)
    nsess = min(sessno(sessno > 0));
    bsi = find((baspred > 0) & (sespred == nsess));
    if numel(bsi) ~= 1
        clearbvqxobjects(sdms);
        error( ...
            'BVQXtools:InternalError', ...
            'Error retrieving unique baseline predictor for session %d.', ...
            sc ...
        );
    end
    sti = find(xX(:, bsi) > 0);
    nti = numel(sti);
    
    % get predictor columns and names
    csi = find((baspred == 0) & (sespred == nsess));
    csn = nampred(csi);
    for pc = 1:numel(csn)
        csn{pc} = regexprep(csn{pc}, ...
            '^sn\(\d+\)\s*([^\s\*]*)\*?.*$', '$1', 'preservecase');
    end
    
    % build SDM
    newsdm = bless(BVQXfile('new:sdm'), 1);
    sdms{sc} = newsdm;
    newsdm.IncludesConstant = 0;
    newsdm.FirstConfoundPredictor = numel(csn) + 1;
    newsdm.NrOfPredictors = numel(csn);
    newsdm.NrOfDataPoints = nti;
    newsdm.PredictorNames = csn(:)';
    newsdm.SDMMatrix = xX(sti, csi);
    newsdm.RTCMatrix = xX(sti, csi);
    
    % saving
    try
        if sessno > 1
            newsdm.SaveAs(sprintf('%s/%s-run%d.sdm', sdmp{1}, sdmp{2}, sc));
        else
            newsdm.SaveAs(sdmfile(:)');
        end
    catch
        clearbvqxobjects(sdms);
        error( ...
            'BVQXtools:BVQXfileError', ...
            'Error saving SDM to file: ''%s''.', ...
            lasterr ...
        );
    end
    
end

% clean objects
if nargout < 2 && ...
    sessno > 1
    clearbvqxobjects(sdms(2:end));
end
sdm = sdms{1};
